#ifndef _EXT4_TOOL_LIB_H_
#define _EXT4_TOOL_LIB_H_

#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for O_DIRECT */
#endif

/* 对超过2GB的大文件进行支持 */
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE

#if defined(__APPLE__) || defined(__BSD__)
#include <stdlib.h>
#define memalign(alignment, size) malloc(size)
#elif defined(_WIN32)
#include <malloc.h>
#define memalign(alignment, size) _aligned_malloc(size, alignment)
#else
#include <stdlib.h>
#endif

#include <inttypes.h>
#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h> // mount 命令
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <malloc.h> // 某些平台需要额外包含
#include <ctype.h>  // 必须包含的头文件

#define MEM_ALIGN_SIZE 512

#define SAFE_CLOSE(fd) \
    do                 \
    {                  \
        if (-1 != fd)  \
        {              \
            close(fd); \
            fd = -1;   \
        }              \
    } while (0) ///< 安全关闭文件描述符

#define TEST_BIT(val, bit) (((val & bit) == bit) && bit != 0)
#define TEST_BIT_Z(val, bit) (((val & bit) == bit))
#define SET_BIT(val, bit) (val |= bit)
#define SET_NBIT(val, bit) (val &= ~bit)

#ifdef offsetof
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#endif

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member)                    \
    ({                                                     \
        const typeof(((type *)0)->member) *__mptr = (ptr); \
        (type *)((char *)__mptr - offsetof(type, member)); \
    })

enum
{
    INFO_LEVEL_1 = 1, /* 重要信息 */
    INFO_LEVEL_2,
    INFO_LEVEL_3, /* 次要信息 */
    INFO_LEVEL_4,
    INFO_LEVEL_5, /* 非常次要信息 */
};

#define EXT4_LVL_SUPER 0x1
#define EXT4_LVL_GDT 0x2
#define EXT4_LVL_BLOCK_MAP 0x4
#define EXT4_LVL_INODE 0x8
#define EXT4_LVL_JNL 0x10
#define EXT4_LVL_JNL_DATA 0x20
#define EXT4_LVL_DATA 0x40

extern int outlvl;
#define pimp(fmt, arg...) printf("[major]:" fmt, ##arg);
#define pinfo(flag, fmt, arg...)                \
    do                                          \
    {                                           \
        if (TEST_BIT(outlvl, flag))             \
            printf("[info]: %-35s" fmt, ##arg); \
    } while (0);
#define pinfo_n(flag, fmt, arg...)  \
    do                              \
    {                               \
        if (TEST_BIT(outlvl, flag)) \
            printf(fmt, ##arg);     \
    } while (0);
#define pwarn(fmt, arg...) printf("[warning]:" fmt "\n", ##arg);
#define perr(fmt, arg...) printf("[error]:%s :" fmt "\n", __func__, ##arg);

/* inode state */
enum
{
    EXT4_INODE_USE = 0,
    EXT4_INODE_UNUSE,
    EXT4_INODE_NOT_INIT,
};

/* OS. One of:
0	Linux
1	Hurd
2	Masix
3	FreeBSD
4	Lites
*/
enum
{
    EXT4_OS_LINUX = 0,
    EXT4_OS_Hurd,
    EXT4_OS_Masix,
    EXT4_OS_FreeBSD,
    EXT4_OS_Lites,
};

/*
Behaviour when detecting errors. One of:
1	Continue
2	Remount read-only
3	Panic
*/
enum
{
    EXT4_SERR_Continue = 1,
    EXT4_SERR_Remount,
    EXT4_SERR_Panic,
};

/*
File system state. Valid values are:
0x0001	Cleanly umounted
0x0002	Errors detected
0x0004	Orphans being recovered
*/
enum
{
    EXT4_STATE_Cleanly = 1,
    EXT4_STATE_Errors = 2,
    EXT4_STATE_Orphans = 4,
};

/*Magic signature, 0xEF53*/
#define EXT4_Magic 0xEF53

/*
Revision level. One of:
0	Original format
1	v2 format w/ dynamic inode sizes
*/
enum
{
    EXT4_REV_LVL_Original = 0,
    EXT4_REV_LVL_v2,
};

/*
Compatible feature set flags. Kernel can still read/write this fs even if it doesn't understand a flag; e2fsck will
not attempt to fix a filesystem with any unknown COMPAT flags. Any of:

0x1	Directory preallocation (COMPAT_DIR_PREALLOC).

0x2	"imagic inodes". Used by AFS to indicate inodes that are not linked into the directory namespace. Inodes marked with
this flag will not be added to lost+found by e2fsck. (COMPAT_IMAGIC_INODES).

0x4	Has a journal (COMPAT_HAS_JOURNAL).

0x8	Supports extended attributes (COMPAT_EXT_ATTR).

0x10 Has reserved GDT blocks for filesystem expansion. Requires RO_COMPAT_SPARSE_SUPER. (COMPAT_RESIZE_INODE).

0x20 Has indexed directories. (COMPAT_DIR_INDEX).

0x40 "Lazy BG". Not in Linux kernel, seems to have been for uninitialized block groups? (COMPAT_LAZY_BG).

0x80 "Exclude inode". Intended for filesystem snapshot feature, but not used. (COMPAT_EXCLUDE_INODE).

0x100 "Exclude bitmap". Seems to be used to indicate the presence of snapshot-related exclude bitmaps? Not defined in
kernel or used in e2fsprogs. (COMPAT_EXCLUDE_BITMAP).

0x200 Sparse Super Block, v2. If this flag is set, the SB field s_backup_bgs points to the two block groups that
contain backup superblocks. (COMPAT_SPARSE_SUPER2).
*/
#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
#define EXT4_FEATURE_COMPAT_LAZY_BG 0x0040
#define EXT4_FEATURE_COMPAT_EXCLUDE_INODE 0x0080
#define EXT4_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100
#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200

union feature_compat
{
    int feature_compat_dat;
    struct
    {
        int dir_prealloc : 1;
        int imagic_inodes : 1;
        int has_journal : 1;
        int ext_attr : 1;

        int resize_inode : 1;
        int dir_index : 1;
        int lazy_bg : 1;
        int exclude_inode : 1;

        int exclude_bitmap : 1;
        int sparse_super2 : 1;
    };
};

/*
Incompatible feature set. If the kernel or e2fsck doesn't understand one of these bits, it will refuse to mount or
attempt to repair the filesystem. Any of:

0x1	Compression. Not implemented. (INCOMPAT_COMPRESSION).

0x2	Directory entries record the file type. See ext4_dir_entry_2 below. (INCOMPAT_FILETYPE).

0x4	Filesystem needs journal recovery. (INCOMPAT_RECOVER).

0x8	Filesystem has a separate journal device. (INCOMPAT_JOURNAL_DEV).

0x10	Meta block groups. See the earlier discussion of this feature. (INCOMPAT_META_BG).

0x40	Files in this filesystem use extents. (INCOMPAT_EXTENTS).

0x80	Enable a filesystem size over 2^32 blocks. (INCOMPAT_64BIT).

0x100	Multiple mount protection. Prevent multiple hosts from mounting the filesystem concurrently by updating a
reserved block periodically while mounted and checking this at mount time to determine if the filesystem is in use on
another host. (INCOMPAT_MMP).

0x200	Flexible block groups. See the earlier discussion of this feature. (INCOMPAT_FLEX_BG).

0x400	Inodes can be used to store large extended attribute values (INCOMPAT_EA_INODE).

0x1000	Data in directory entry. Allow additional data fields to be stored in each dirent, after struct ext4_dirent. The
presence of extra data is indicated by flags in the high bits of ext4_dirent file type flags (above EXT4_FT_MAX). The
flag EXT4_DIRENT_LUFID = 0x10 is used to store a 128-bit File Identifier for Lustre. The flag EXT4_DIRENT_IO64 = 0x20 is
used to store the high word of 64-bit inode numbers. Feature still in development. (INCOMPAT_DIRDATA).

0x2000	Metadata checksum seed is stored in the superblock. This feature enables the administrator to change the UUID of
a metadata_csum filesystem while the filesystem is mounted; without it, the checksum definition requires all metadata
blocks to be rewritten. (INCOMPAT_CSUM_SEED).

0x4000	Large directory >2GB or 3-level htree. Prior to this feature, directories could not be larger than 4GiB and
could not have an htree more than 2 levels deep. If this feature is enabled, directories can be larger than 4GiB and
have a maximum htree depth of 3. (INCOMPAT_LARGEDIR).

0x8000	Data in inode. Small files or directories are stored directly in the inode i_blocks and/or xattr space.
(INCOMPAT_INLINE_DATA).

0x10000	Encrypted inodes are present on the filesystem (INCOMPAT_ENCRYPT).
*/
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004     /* Needs recovery */
#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */
#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000  /* data in dirent */
#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000    /* >2GB or 3-lvl htree */
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000

union feature_incompat
{
    int feature_incompat_dat;
    struct
    {
        int compression : 1;
        int file_type : 1;
        int journal_recovery : 1;
        int journal_device : 1;

        int meta_bg : 1;
        int nc1 : 1;
        int use_extents : 1;
        int use_64bit : 1;

        int mul_mount_protection : 1;
        int flex_bg : 1;
        int ea_inode : 1;
        int nc2 : 1;

        int dirdata : 1;
        int csum_seed : 1;
        int large_dir : 1;
        int inline_data : 1;

        int encrypt : 1;
    };
};

/*
Readonly-compatible feature set. If the kernel doesn't understand one of these bits, it can still mount read-only, but
e2fsck will refuse to modify the filesystem. Any of:

0x1	Sparse superblocks. See the earlier discussion of this feature. (RO_COMPAT_SPARSE_SUPER).

0x2	Allow storing files larger than 2GiB (RO_COMPAT_LARGE_FILE).

0x4	Was intended for use with htree directories, but was not needed. Not used in kernel or e2fsprogs
(RO_COMPAT_BTREE_DIR).

0x8	This filesystem has files whose space usage is stored in i_blocks in units of filesystem blocks, not 512-byte
sectors. Inodes using this feature will be marked with EXT4_INODE_HUGE_FILE. (RO_COMPAT_HUGE_FILE)

0x10	Group descriptors have checksums. In addition to detecting corruption, this is useful for lazy formatting with
uninitialized groups (RO_COMPAT_GDT_CSUM).

0x20	Indicates that the old ext3 32,000 subdirectory limit no longer applies. A directory's i_links_count will be set
to 1 if it is incremented past 64,999. (RO_COMPAT_DIR_NLINK).

0x40	Indicates that large inodes exist on this filesystem, storing extra fields after EXT2_GOOD_OLD_INODE_SIZE.
(RO_COMPAT_EXTRA_ISIZE).

0x80	This filesystem has a snapshot. Not implemented in ext4. (RO_COMPAT_HAS_SNAPSHOT).

0x100	Quota is handled transactionally with the journal (RO_COMPAT_QUOTA).

0x200	This filesystem supports "bigalloc", which means that filesystem block allocation bitmaps are tracked in units
of clusters (of blocks) instead of blocks (RO_COMPAT_BIGALLOC).

0x400	This filesystem supports metadata checksumming. (RO_COMPAT_METADATA_CSUM; implies RO_COMPAT_GDT_CSUM, though
GDT_CSUM must not be set)

0x800	Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs. (RO_COMPAT_REPLICA).

0x1000	Read-only filesystem image; the kernel will not mount this image read-write and most tools will refuse to write
to the image. (RO_COMPAT_READONLY).

0x2000	Filesystem tracks project quotas. (RO_COMPAT_PROJECT)
*/
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100
#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200
/*
 * METADATA_CSUM also enables group descriptor checksums (GDT_CSUM).  When
 * METADATA_CSUM is set, group descriptor checksums use the same algorithm as
 * all other data structures' checksums.  However, the METADATA_CSUM and
 * GDT_CSUM bits are mutually exclusive.
 */
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000
#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000

union feature_rocompat
{
    int feature_rocompat_dat;
    struct
    {
        int sparse_super : 1;
        int large_file : 1;
        int btree_dir : 1;
        int huge_dir : 1;

        int gdt_csum : 1;
        int dir_nlink : 1;
        int extra_isize : 1;
        int nc1 : 1;

        int quota : 1;
        int bigalloc : 1;
        int metadata_csum : 1;
        int nc2 : 1;

        int readonly : 1;
        int project : 1;
    };
};

/*
Default mount options. Any of:
0x0001	Print debugging info upon (re)mount. (EXT4_DEFM_DEBUG)

0x0002	New files take the gid of the containing directory (instead of the fsgid of the current process).
(EXT4_DEFM_BSDGROUPS)

0x0004	Support userspace-provided extended attributes. (EXT4_DEFM_XATTR_USER)

0x0008	Support POSIX access control lists (ACLs). (EXT4_DEFM_ACL)

0x0010	Do not support 32-bit UIDs. (EXT4_DEFM_UID16)

0x0020	All data and metadata are commited to the journal. (EXT4_DEFM_JMODE_DATA)

0x0040	All data are flushed to the disk before metadata are committed to the journal. (EXT4_DEFM_JMODE_ORDERED)

0x0060	Data ordering is not preserved; data may be written after the metadata has been written. (EXT4_DEFM_JMODE_WBACK)

0x0100	Disable write flushes. (EXT4_DEFM_NOBARRIER)

0x0200	Track which blocks in a filesystem are metadata and therefore should not be used as data blocks. This option
will be enabled by default on 3.18, hopefully. (EXT4_DEFM_BLOCK_VALIDITY)

0x0400	Enable DISCARD support, where the storage device is told about blocks becoming unused. (EXT4_DEFM_DISCARD)

0x0800	Disable delayed allocation. (EXT4_DEFM_NODELALLOC)
*/
/*
 * Default mount options
 */
#define EXT4_DEFM_DEBUG 0x0001
#define EXT4_DEFM_BSDGROUPS 0x0002
#define EXT4_DEFM_XATTR_USER 0x0004
#define EXT4_DEFM_ACL 0x0008
#define EXT4_DEFM_UID16 0x0010
#define EXT4_DEFM_JMODE 0x0060
#define EXT4_DEFM_JMODE_DATA 0x0020
#define EXT4_DEFM_JMODE_ORDERED 0x0040
#define EXT4_DEFM_JMODE_WBACK 0x0060
#define EXT4_DEFM_NOBARRIER 0x0100
#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
#define EXT4_DEFM_DISCARD 0x0400
#define EXT4_DEFM_NODELALLOC 0x0800

/*********************************************superblock相关**********************************************/

/*
 * Revision levels
 */
#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */
#define EXT4_DYNAMIC_REV 1  /* V2 format w/ dynamic inode sizes */

#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV
#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV

/*
Miscellaneous flags. Any of:
0x0001	Signed directory hash in use.
0x0002	Unsigned directory hash in use.
0x0004	To test development code.
*/
enum
{
    EXT4_MISC_F_Signed = 1,
    EXT4_MISC_F_Unsigned = 2,
    EXT4_MISC_F_test = 4,
};

struct ext4_super_block
{
    /*00*/ __le32 s_inodes_count;      /* Inodes count */
    __le32 s_blocks_count_lo;          /* Blocks count */
    __le32 s_r_blocks_count_lo;        /* Reserved blocks count */
    __le32 s_free_blocks_count_lo;     /* Free blocks count */
    /*10*/ __le32 s_free_inodes_count; /* Free inodes count */
    __le32 s_first_data_block;         /* First Data Block */
    __le32 s_log_block_size;           /* Block size ,Block size is 2 ^ (10 + s_log_block_size). */
    __le32 s_log_cluster_size;         /* Allocation cluster size */
    /*20*/ __le32 s_blocks_per_group;  /* # Blocks per group */
    __le32 s_clusters_per_group;       /* # Clusters per group */
    __le32 s_inodes_per_group;         /* # Inodes per group */
    __le32 s_mtime;                    /* Mount time */
    /*30*/ __le32 s_wtime;             /* Write time */
    __le16 s_mnt_count;                /* Mount count */
    __le16 s_max_mnt_count;            /* Maximal mount count */
    __le16 s_magic;                    /* Magic signature */
    __le16 s_state;                    /* File system state */
    __le16 s_errors;                   /* Behaviour when detecting errors */
    __le16 s_minor_rev_level;          /* minor revision level */
    /*40*/ __le32 s_lastcheck;         /* time of last check */
    __le32 s_checkinterval;            /* max. time between checks */
    __le32 s_creator_os;               /* OS */
    __le32 s_rev_level;                /* Revision level */
    /*50*/ __le16 s_def_resuid;        /* Default uid for reserved blocks */
    __le16 s_def_resgid;               /* Default gid for reserved blocks */
    /*
     * These fields are for EXT4_DYNAMIC_REV superblocks only.
     *
     * Note: the difference between the compatible feature set and
     * the incompatible feature set is that if there is a bit set
     * in the incompatible feature set that the kernel doesn't
     * know about, it should refuse to mount the filesystem.
     *
     * e2fsck's requirements are more strict; if it doesn't know
     * about a feature in either the compatible or incompatible
     * feature set, it must abort and not try to meddle with
     * things it doesn't understand...
     */
    __le32 s_first_ino;                     /* First non-reserved inode */
    __le16 s_inode_size;                    /* size of inode structure */
    __le16 s_block_group_nr;                /* block group # of this superblock */
    __le32 s_feature_compat;                /* compatible feature set */
    /*60*/ __le32 s_feature_incompat;       /* incompatible feature set */
    __le32 s_feature_ro_compat;             /* readonly-compatible feature set */
    /*68*/ __u8 s_uuid[16];                 /* 128-bit uuid for volume */
    /*78*/ char s_volume_name[16];          /* volume name */
    /*88*/ char s_last_mounted[64];         /* directory where last mounted */
    /*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */

    /*
     * Performance hints.  Directory preallocation should only
     * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
     */
    __u8 s_prealloc_blocks;       /* Nr of blocks to try to preallocate*/
    __u8 s_prealloc_dir_blocks;   /* Nr to preallocate for dirs */
    __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */

    /*
     * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
     */
    /*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
    /*E0*/ __le32 s_journal_inum;   /* inode number of journal file */
    __le32 s_journal_dev;           /* device number of journal file */
    __le32 s_last_orphan;           /* start of list of inodes to delete */
    __le32 s_hash_seed[4];          /* HTREE hash seed */
    __u8 s_def_hash_version;        /* Default hash version to use */
    __u8 s_jnl_backup_type;
    __le16 s_desc_size; /* size of group descriptor */
    /*100*/ __le32 s_default_mount_opts;
    __le32 s_first_meta_bg;  /* First metablock block group */
    __le32 s_mkfs_time;      /* When the filesystem was created */
    __le32 s_jnl_blocks[17]; /* Backup of the journal inode */

    /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
    /*150*/ __le32 s_blocks_count_hi; /* Blocks count */
    __le32 s_r_blocks_count_hi;       /* Reserved blocks count */
    __le32 s_free_blocks_count_hi;    /* Free blocks count */
    __le16 s_min_extra_isize;         /* All inodes have at least # bytes */
    __le16 s_want_extra_isize;        /* New inodes should reserve # bytes */
    __le32 s_flags;                   /* Miscellaneous flags */
    __le16 s_raid_stride;             /* RAID stride */
    __le16 s_mmp_update_interval;     /* # seconds to wait in MMP checking */
    __le64 s_mmp_block;               /* Block for multi-mount protection */
    __le32 s_raid_stripe_width;       /* blocks on all data disks (N*stride)*/
    __u8 s_log_groups_per_flex;       /* FLEX_BG group size */
    __u8 s_checksum_type;             /* metadata checksum algorithm used */
    __u8 s_encryption_level;          /* versioning level for encryption */
    __u8 s_reserved_pad;              /* Padding to next 32bits */
    __le64 s_kbytes_written;          /* nr of lifetime kilobytes written */
    __le32 s_snapshot_inum;           /* Inode number of active snapshot */
    __le32 s_snapshot_id;             /* sequential ID of active snapshot */
    __le64 s_snapshot_r_blocks_count; /* reserved blocks for active
                         snapshot's future use */
    __le32 s_snapshot_list;           /* inode number of the head of the
                                       on-disk snapshot list */
#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
    __le32 s_error_count;        /* number of fs errors */
    __le32 s_first_error_time;   /* first time an error happened */
    __le32 s_first_error_ino;    /* inode involved in first error */
    __le64 s_first_error_block;  /* block involved of first error */
    __u8 s_first_error_func[32]; /* function where the error happened */
    __le32 s_first_error_line;   /* line number where error happened */
    __le32 s_last_error_time;    /* most recent time of an error */
    __le32 s_last_error_ino;     /* inode involved in last error */
    __le32 s_last_error_line;    /* line number where error happened */
    __le64 s_last_error_block;   /* block involved of last error */
    __u8 s_last_error_func[32];  /* function where the error happened */
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
    __u8 s_mount_opts[64];
    __le32 s_usr_quota_inum;    /* inode for tracking user quota */
    __le32 s_grp_quota_inum;    /* inode for tracking group quota */
    __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
    __le32 s_backup_bgs[2];     /* groups with sparse_super2 SBs */
    __u8 s_encrypt_algos[4];    /* Encryption algorithms in use  */
    __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
    __le32 s_lpf_ino;           /* Location of the lost+found inode */
    __le32 s_prj_quota_inum;    /* inode for tracking project quota */
    __le32 s_checksum_seed;     /* crc32c(uuid) if csum_seed set */
    __le32 s_reserved[98];      /* Padding to the end of the block */
    __le32 s_checksum;          /* crc32c(superblock) */
};
#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)

#define EXT4_SB_OFFSET 1024
#define EXT4_SB_LEN 1024

#define READ_MAX_BUF_LEN 40960

/*********************************************GDT相关**********************************************/

#define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
#define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */
#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
union bg_flags_u
{
    uint16_t bg_flags_dat;
    struct
    {
        uint16_t inode_uninit : 1;
        uint16_t block_uninit : 1;
        uint16_t inode_zeroed : 1;
    };
};

/*
 * Structure of a blocks group descriptor Total size is 64 bytes.
 */
struct ext4_group_desc
{
    __le32 bg_block_bitmap_lo;      /* Blocks bitmap block */
    __le32 bg_inode_bitmap_lo;      /* Inodes bitmap block */
    __le32 bg_inode_table_lo;       /* Inodes table block */
    __le16 bg_free_blocks_count_lo; /* Free blocks count */
    __le16 bg_free_inodes_count_lo; /* Free inodes count */
    __le16 bg_used_dirs_count_lo;   /* Directories count */
    __le16 bg_flags;                /* EXT4_BG_flags (INODE_UNINIT, etc) */
    __le32 bg_exclude_bitmap_lo;    /* Exclude bitmap for snapshots */
    __le16 bg_block_bitmap_csum_lo; /* crc32c(s_uuid+grp_num+bbitmap) LE */
    __le16 bg_inode_bitmap_csum_lo; /* crc32c(s_uuid+grp_num+ibitmap) LE */
    __le16 bg_itable_unused_lo;     /* Unused inodes count */
    __le16 bg_checksum;             /* crc16(sb_uuid+group+desc) */

    /* These fields only exist if the 64bit feature is enabled and s_desc_size > 32. */
    /* 只有开启了64bit才会使用以下字节 */
    /*0x20*/ __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
    __le32 bg_inode_bitmap_hi;          /* Inodes bitmap block MSB */
    __le32 bg_inode_table_hi;           /* Inodes table block MSB */
    __le16 bg_free_blocks_count_hi;     /* Free blocks count MSB */
    __le16 bg_free_inodes_count_hi;     /* Free inodes count MSB */
    __le16 bg_used_dirs_count_hi;       /* Directories count MSB */
    __le16 bg_itable_unused_hi;         /* Unused inodes count MSB */
    __le32 bg_exclude_bitmap_hi;        /* Exclude bitmap block MSB */
    __le16 bg_block_bitmap_csum_hi;     /* crc32c(s_uuid+grp_num+bbitmap) BE */
    __le16 bg_inode_bitmap_csum_hi;     /* crc32c(s_uuid+grp_num+ibitmap) BE */
    __u32 bg_reserved;
};

#define EXT4_GROUP_DESC_LEN 32
#define EXT4_GROUP_DESC_64bit_LEN 64

#define EXT4_NDIR_BLOCKS 12
#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)

/*********************************************inode相关**********************************************/

/* File mode */
#define EXT4_S_IXOTH 0x1 //(Others may execute)
#define EXT4_S_IWOTH 0x2 //(Others may write)
#define EXT4_S_IROTH 0x4 // Others may read)

#define EXT4_S_IXGRP 0x8  //(Group members may execute)
#define EXT4_S_IWGRP 0x10 //(Group members may write)
#define EXT4_S_IRGRP 0x20 //(Group members may read)

#define EXT4_S_IXUSR 0x40  //(Owner may execute)
#define EXT4_S_IWUSR 0x80  //(Owner may write)
#define EXT4_S_IRUSR 0x100 //(Owner may read)

#define EXT4_S_ISVTX 0x200 //(Sticky bit)
#define EXT4_S_ISGID 0x400 //(Set GID)
#define EXT4_S_ISUID 0x800 //(Set UID)

/* These are mutually-exclusive file types: */
#define EXT4_S_IFIFO 0x1000  //(FIFO)
#define EXT4_S_IFCHR 0x2000  //(Character device)
#define EXT4_S_IFDIR 0x4000  //(Directory)
#define EXT4_S_IFBLK 0x6000  //(Block device)
#define EXT4_S_IFREG 0x8000  //(Regular file)
#define EXT4_S_IFLNK 0xA000  //(Symbolic link)
#define EXT4_S_IFSOCK 0xC000 //(Socket)

/*
 * Inode flags
 */
#define EXT4_SECRM_FL 0x00000001     /* Secure deletion(not implemented) */
#define EXT4_UNRM_FL 0x00000002      /* Undelete(not implemented) */
#define EXT4_COMPR_FL 0x00000004     /* Compress file(not really implemented) */
#define EXT4_SYNC_FL 0x00000008      /* Synchronous updates */
#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT4_APPEND_FL 0x00000020    /* writes to file may only append */
#define EXT4_NODUMP_FL 0x00000040    /* do not dump file */
#define EXT4_NOATIME_FL 0x00000080   /* do not update atime */
/* Reserved for compression usage... */
#define EXT4_DIRTY_FL 0x00000100    /* Dirty compressed file(not used) */
#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters(not used) */
#define EXT4_NOCOMPR_FL 0x00000400  /* Don't compress (not used)*/
/* nb: was previously EXT2_ECOMPR_FL */
#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file(never used) */
/* End compression flags --- maybe not all used */
#define EXT4_INDEX_FL 0x00001000        /* hash-indexed directory */
#define EXT4_IMAGIC_FL 0x00002000       /* AFS directory */
#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
#define EXT4_NOTAIL_FL 0x00008000       /* file tail should not be merged */
#define EXT4_DIRSYNC_FL 0x00010000      /* dirsync behaviour (directories only) */
#define EXT4_TOPDIR_FL 0x00020000       /* Top of directory hierarchies*/
#define EXT4_HUGE_FILE_FL 0x00040000    /* Set to each huge file */
#define EXT4_EXTENTS_FL 0x00080000      /* Inode uses extents */
#define EXT4_EA_INODE_FL 0x00200000     /* Inode used for large EA */
#define EXT4_EOFBLOCKS_FL 0x00400000    /* Blocks allocated beyond EOF */
#define EXT4_INLINE_DATA_FL 0x10000000  /* Inode has inline data. */
#define EXT4_PROJINHERIT_FL 0x20000000  /* Create with parents projid */
#define EXT4_RESERVED_FL 0x80000000     /* reserved for ext4 lib */

union inode_flag
{
    int inode_flag_dat;
    struct
    {
        int secrm : 1;
        int unrm : 1;
        int compr : 1;
        int sync : 1;

        int immutable : 1;
        int append : 1;
        int nodump : 1;
        int noatime : 1;

        int dirty : 1;
        int comprblk : 1;
        int nocompr : 1;
        int encrypt : 1;

        int index : 1;
        int imagic : 1;
        int journal : 1;
        int notail : 1;

        int dirsync : 1;
        int topdir : 1;
        int hugefile : 1;
        int extents : 1;

        int nc1 : 1;
        int eainode : 1;
        int eofbolck : 1;
        int nc2 : 1;

        int nc3 : 1;
        int nc4 : 1;
        int nc5 : 1;
        int nc6 : 1;

        int inlinedata : 1;
        int projinherit : 1;
        int nc7 : 1;
        int reserved : 1;
    };
};

/*
File flags. Any of:
0x1	This file requires secure deletion (EXT4_SECRM_FL). (not implemented)
0x2	This file should be preserved, should undeletion be desired (EXT4_UNRM_FL). (not implemented)
0x4	File is compressed (EXT4_COMPR_FL). (not really implemented)
0x8	All writes to the file must be synchronous (EXT4_SYNC_FL).
0x10	File is immutable (EXT4_IMMUTABLE_FL).
0x20	File can only be appended (EXT4_APPEND_FL).
0x40	The dump(1) utility should not dump this file (EXT4_NODUMP_FL).
0x80	Do not update access time (EXT4_NOATIME_FL).
0x100	Dirty compressed file (EXT4_DIRTY_FL). (not used)
0x200	File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used)
0x400	Do not compress file (EXT4_NOCOMPR_FL). (not used)
0x800	Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was EXT4_ECOMPR_FL (compression error), which
was never used.
0x1000	Directory has hashed indexes (EXT4_INDEX_FL).
0x2000	AFS magic directory (EXT4_IMAGIC_FL).
0x4000	File data must always be written through the journal (EXT4_JOURNAL_DATA_FL).
0x8000	File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4)
0x10000	All directory entry data should be written synchronously (see dirsync) (EXT4_DIRSYNC_FL).
0x20000	Top of directory hierarchy (EXT4_TOPDIR_FL).
0x40000	This is a huge file (EXT4_HUGE_FILE_FL).
0x80000	Inode uses extents (EXT4_EXTENTS_FL).
0x200000	Inode stores a large extended attribute value in its data blocks (EXT4_EA_INODE_FL).
0x400000	This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL). (deprecated)
0x01000000	Inode is a snapshot (EXT4_SNAPFILE_FL). (not in mainline)
0x04000000	Snapshot is being deleted (EXT4_SNAPFILE_DELETED_FL). (not in mainline)
0x08000000	Snapshot shrink has completed (EXT4_SNAPFILE_SHRUNK_FL). (not in mainline)
0x10000000	Inode has inline data (EXT4_INLINE_DATA_FL).
0x20000000	Create children with the same project ID (EXT4_PROJINHERIT_FL).
0x80000000	Reserved for ext4 library (EXT4_RESERVED_FL).
Aggregate flags:
0x4BDFFF	User-visible flags.
0x4B80FF	User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and EXT4_EXTENTS_FL can be set with setattr,
they are not in the kernel's EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of these flags in a
special manner and they are masked out of the set of flags that are saved directly to i_flags.

*/

/*
 * Structure of an inode on the disk
 */
struct ext4_inode
{
    /* 看上面的宏定义规定了文件的mode */
    __le16 i_mode;        /* File mode */
    __le16 i_uid;         /* Low 16 bits of Owner Uid */
    __le32 i_size_lo;     /* Size in bytes */
    __le32 i_atime;       /* Access time */
    __le32 i_ctime;       /* Inode Change time */
    __le32 i_mtime;       /* Modification time */
    __le32 i_dtime;       /* Deletion Time */
    __le16 i_gid;         /* Low 16 bits of Group Id */
    __le16 i_links_count; /* Links count */
    __le32 i_blocks_lo;   /* Blocks count */

    /* 看上面宏定义规定的flag状态 */
    __le32 i_flags; /* File flags */
    union
    {
        struct
        {
            __le32 l_i_version;
        } linux1;
        struct
        {
            __u32 h_i_translator;
        } hurd1;
        struct
        {
            __u32 m_i_reserved1;
        } masix1;
    } osd1;                        /* OS dependent 1 */
    __le32 i_block[EXT4_N_BLOCKS]; /* Pointers to blocks */
    __le32 i_generation;           /* File version (for NFS) */
    __le32 i_file_acl_lo;          /* File ACL */
    __le32 i_size_high;
    __le32 i_obso_faddr; /* Obsoleted fragment address */
    union
    {
        struct
        {
            __le16 l_i_blocks_high; /* were l_i_reserved1 */
            __le16 l_i_file_acl_high;
            __le16 l_i_uid_high;    /* these 2 fields */
            __le16 l_i_gid_high;    /* were reserved2[0] */
            __le16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) LE */
            __le16 l_i_reserved;
        } linux2;
        struct
        {
            __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
            __u16 h_i_mode_high;
            __u16 h_i_uid_high;
            __u16 h_i_gid_high;
            __u32 h_i_author;
        } hurd2;
        struct
        {
            __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
            __le16 m_i_file_acl_high;
            __u32 m_i_reserved2[2];
        } masix2;
    } osd2; /* OS dependent 2 */
    __le16 i_extra_isize;
    __le16 i_checksum_hi;  /* crc32c(uuid+inum+inode) BE */
    __le32 i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
    __le32 i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
    __le32 i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
    __le32 i_crtime;       /* File Creation time */
    __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
    __le32 i_version_hi;   /* high 32 bits for 64-bit version */
    __le32 i_projid;       /* Project ID */
};

#define INODE_DATA_LEN_128 128
#define INODE_DATA_LEN_256 256

typedef unsigned long long ext4_fsblk_t;
/*
 * This is the extent on-disk structure.
 * It's used at the bottom of the tree.
 */
struct ext4_extent
{
    __le32 ee_block;    /* first logical block extent covers */
    __le16 ee_len;      /* number of blocks covered by extent */
    __le16 ee_start_hi; /* high 16 bits of physical block */
    __le32 ee_start_lo; /* low 32 bits of physical block */
};

/*
 * This is index on-disk structure.
 * It's used at all the levels except the bottom.
 */
struct ext4_extent_idx
{
    __le32 ei_block;   /* index covers logical blocks from 'block' */
    __le32 ei_leaf_lo; /* pointer to the physical block of the next *
                        * level. leaf or next index could be there */
    __le16 ei_leaf_hi; /* high 16 bits of physical block */
    __u16 ei_unused;
};

/*
 * Each block (leaves and indexes), even inode-stored has header.
 */
struct ext4_extent_header
{
    __le16 eh_magic;      /* probably will support different formats */
    __le16 eh_entries;    /* number of valid entries */
    __le16 eh_max;        /* capacity of store in entries */
    __le16 eh_depth;      /* has tree real underlying blocks? */
    __le32 eh_generation; /* generation of the tree */
};

/*
 * Array of ext4_ext_path contains path to some extent.
 * Creation/lookup routines use it for traversal/splitting/etc.
 * Truncate uses it to simulate recursive walking.
 */
struct ext4_ext_path
{
    ext4_fsblk_t p_block;
    __u16 p_depth;
    __u16 p_maxdepth;
    struct ext4_extent *p_ext;
    struct ext4_extent_idx *p_idx;
    struct ext4_extent_header *p_hdr;
    // struct buffer_head		*p_bh;
};

#define EXTENT_LEN sizeof(struct ext4_extent)

#define EXT_FIRST_EXTENT(__hdr__) ((struct ext4_extent *)(((char *)(__hdr__)) + sizeof(struct ext4_extent_header)))
#define EXT_NEXT_EXTENT(__hdr__, entries) \
    ((struct ext4_extent *)(((char *)(__hdr__)) + ((entries + 1) * sizeof(struct ext4_extent_header))))
#define EXT_FIRST_INDEX(__hdr__) ((struct ext4_extent_idx *)(((char *)(__hdr__)) + sizeof(struct ext4_extent_header)))
#define EXT_HAS_FREE_INDEX(__path__) ((__path__)->p_hdr->eh_entries < (__path__)->p_hdr->eh_max)
#define EXT_LAST_EXTENT(__hdr__) (EXT_FIRST_EXTENT((__hdr__)) + ((__hdr__)->eh_entries) - 1)
#define EXT_LAST_INDEX(__hdr__) (EXT_FIRST_INDEX((__hdr__)) + ((__hdr__)->eh_entries) - 1)
#define EXT_MAX_EXTENT(__hdr__) (EXT_FIRST_EXTENT((__hdr__)) + ((__hdr__)->eh_max) - 1)
#define EXT_MAX_INDEX(__hdr__) (EXT_FIRST_INDEX((__hdr__)) + ((__hdr__)->eh_max) - 1)

#define EXT4_EXT_MAGIC (0xf30a)

/************inline data************/

#define EXT4_XATTR_MAGIC 0xEA020000
#define EXT4_XATTR_SYSTEM_DATA "data"

struct ext4_xattr_ibody_header
{
    __le32 h_magic; /* magic number for identification */
};

struct ext4_xattr_entry
{
    __u8 e_name_len;      /* length of name */
    __u8 e_name_index;    /* attribute name index */
    __le16 e_value_offs;  /* offset in disk block of value */
    __le32 e_value_block; /* disk block attribute is stored on (n/i) */
    __le32 e_value_size;  /* size of attribute value */
    __le32 e_hash;        /* hash value of name and value */
    char e_name[0];       /* attribute name */
};

#define XATTR_SYSTEM_DATA_LEN 4
#define XATTR_MAGIC_LEN 4
#define INLINE_DAT_ATTR (sizeof(struct ext4_xattr_entry) + XATTR_MAGIC_LEN) /* 实际长度应为16 */

/*********************************************目录相关**********************************************/
/*
 * Structure of a directory entry
 */
#define EXT4_NAME_LEN 255

struct ext4_dir_entry
{
    __le32 inode;             /* Inode number */
    __le16 rec_len;           /* Directory entry length */
    __le16 name_len;          /* Name length */
    char name[EXT4_NAME_LEN]; /* File name */
};

/*
 * The new version of the directory entry.  Since EXT4 structures are
 * stored in intel byte order, and the name_len field could never be
 * bigger than 255 chars, it's safe to reclaim the extra byte for the
 * file_type field.
 */
struct ext4_dir_entry_2
{
    __le32 inode;   /* Inode number */
    __le16 rec_len; /* Directory entry length */
    __u8 name_len;  /* Name length */
    __u8 file_type;
    char name[EXT4_NAME_LEN]; /* File name */
};

#define EXT4_FT_UNKNOWN 0
#define EXT4_FT_REG_FILE 1
#define EXT4_FT_DIR 2
#define EXT4_FT_CHRDEV 3
#define EXT4_FT_BLKDEV 4
#define EXT4_FT_FIFO 5
#define EXT4_FT_SOCK 6
#define EXT4_FT_SYMLINK 7

// 链表节点结构（存储目录条目关键信息）
typedef struct dir_entry_node
{
    uint32_t inode; // 主机字节序的inode号
    uint32_t root_dir_inode;
    uint8_t file_type;
    char *name; // 动态分配的文件名
    struct dir_entry_node *next;
} dir_entry_node_t;

/*********************************************jbd2日志相关**********************************************/
#define JBD2_MAGIC_NUMBER 0xc03b3998U

/*
 * Descriptor block types:
 */

#define JBD2_DESCRIPTOR_BLOCK 1
#define JBD2_COMMIT_BLOCK 2
#define JBD2_SUPERBLOCK_V1 3
#define JBD2_SUPERBLOCK_V2 4
#define JBD2_REVOKE_BLOCK 5

/* Definitions for the journal tag flags word: */
#define JBD2_FLAG_ESCAPE 1    /* on-disk block is escaped */
#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */
#define JBD2_FLAG_DELETED 4   /* block deleted by this transaction */
#define JBD2_FLAG_LAST_TAG 8  /* last tag in this descriptor block */

/*
 * Standard header for all descriptor blocks:
 */
typedef struct journal_header_s
{
    __be32 h_magic;
    __be32 h_blocktype;
    __be32 h_sequence;
} journal_header_t;
/*
 * The journal superblock.  All fields are in big-endian byte order.
 */
typedef struct journal_superblock_s
{
    /* 0x0000 */
    journal_header_t s_header;

    /* 0x000C */
    /* Static information describing the journal */
    __be32 s_blocksize; /* journal device blocksize */
    __be32 s_maxlen;    /* total blocks in journal file */
    __be32 s_first;     /* first block of log information */

    /* 0x0018 */
    /* Dynamic information describing the current state of the log */
    __be32 s_sequence; /* first commit ID expected in log */
    __be32 s_start;    /* blocknr of start of log */

    /* 0x0020 */
    /* Error value, as set by jbd2_journal_abort(). */
    __be32 s_errno;

    /* 0x0024 */
    /* Remaining fields are only valid in a version-2 superblock */
    __be32 s_feature_compat;    /* compatible feature set */
    __be32 s_feature_incompat;  /* incompatible feature set */
    __be32 s_feature_ro_compat; /* readonly-compatible feature set */
    /* 0x0030 */
    __u8 s_uuid[16]; /* 128-bit uuid for journal */

    /* 0x0040 */
    __be32 s_nr_users; /* Nr of filesystems sharing log */

    __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/

    /* 0x0048 */
    __be32 s_max_transaction; /* Limit of journal blocks per trans.*/
    __be32 s_max_trans_data;  /* Limit of data blocks per trans. */

    /* 0x0050 */
    __u8 s_checksum_type; /* checksum type */
    __u8 s_padding2[3];
    __u32 s_padding[42];
    __be32 s_checksum; /* crc32c(superblock) */

    /* 0x0100 */
    __u8 s_users[16 * 48]; /* ids of all fs'es sharing the log */
                           /* 0x0400 */
} journal_superblock_t;

/* Use the jbd2_{has,set,clear}_feature_* helpers; these will be removed */
#define JBD2_HAS_COMPAT_FEATURE(j, mask) \
    ((j)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2 && TEST_BIT((j)->s_feature_compat, mask))
#define JBD2_HAS_RO_COMPAT_FEATURE(j, mask) \
    ((j)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2 && TEST_BIT((j)->s_feature_ro_compat, mask))
#define JBD2_HAS_INCOMPAT_FEATURE(j, mask) \
    ((j)->s_header.h_blocktype == JBD2_SUPERBLOCK_V2 && TEST_BIT((j)->s_feature_incompat, mask))

#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001

#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
#define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008
#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010

/*
 * The block tag: used to describe a single buffer in the journal.
 * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this
 * raw struct shouldn't be used for pointer math or sizeof() - use
 * journal_tag_bytes(journal) instead to compute this.
 */
typedef struct journal_block_tag3_s
{
    __be32 t_blocknr;      /* The on-disk block number */
    __be32 t_flags;        /* See below */
    __be32 t_blocknr_high; /* most-significant high 32bits. */
    __be32 t_checksum;     /* crc32c(uuid+seq+block) */
} journal_block_tag3_t;

typedef struct journal_block_tag_s
{
    __be32 t_blocknr;      /* The on-disk block number */
    __be16 t_checksum;     /* truncated crc32c(uuid+seq+block) */
    __be16 t_flags;        /* See below */
    __be32 t_blocknr_high; /* most-significant high 32bits. */
} journal_block_tag_t;

typedef struct jbd2_journal_revoke_header_s
{
    journal_header_t r_header;
    __be32 r_count; /* Count of bytes used in the block */
} jbd2_journal_revoke_header_t;

#define REVOKE_FLAG 0x7EDABC12
#define COMMIT_FLAG 0x71234567

/* 如果tag太多就不再解析了 */
#define MAX_TAG_NUM 128

static inline bool jbd2_has_feature_csum3(journal_superblock_t *journal)
{
    return JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3);
}

static inline bool jbd2_has_feature_csum2(journal_superblock_t *journal)
{
    return JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2);
}

static inline bool jbd2_has_feature_64bit(journal_superblock_t *journal)
{
    return JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT);
}

/*
 * Checksum types.
 */
#define JBD2_CRC32_CHKSUM 1
#define JBD2_MD5_CHKSUM 2
#define JBD2_SHA1_CHKSUM 3
#define JBD2_CRC32C_CHKSUM 4

#define JBD2_CRC32_CHKSUM_SIZE 4

#define JBD2_CHECKSUM_BYTES (32 / sizeof(uint32_t))
/*
 * Commit block header for storing transactional checksums:
 *
 * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum*
 * fields are used to store a checksum of the descriptor and data blocks.
 *
 * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum
 * field is used to store crc32c(uuid+commit_block).  Each journal metadata
 * block gets its own checksum, and data block checksums are stored in
 * journal_block_tag (in the descriptor).  The other h_chksum* fields are
 * not used.
 *
 * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses
 * journal_block_tag3_t to store a full 32-bit checksum.  Everything else
 * is the same as v2.
 *
 * Checksum v1, v2, and v3 are mutually exclusive features.
 */
struct commit_header
{
    __be32 h_magic;
    __be32 h_blocktype;
    __be32 h_sequence;
    unsigned char h_chksum_type;
    unsigned char h_chksum_size;
    unsigned char h_padding[2];
    __be32 h_chksum[JBD2_CHECKSUM_BYTES];
    __be64 h_commit_sec;
    __be32 h_commit_nsec;
};

static inline void swfun(uint8_t *buf, uint8_t len)
{
    uint8_t i = 0;
    uint8_t t;
    for (i = 0; i < (len >> 1); i++)
    {
        t = buf[i];
        buf[i] = buf[len - 1 - i];
        buf[len - 1 - i] = t;
    }
}

#define conversion(data)                       \
    {                                          \
        swfun((uint8_t *)&data, sizeof(data)); \
    }

/*********************************************ext4tool**********************************************/
#define JOURNAL_P_WORD "journal"

#define B_ATTR_SB 0x01
#define B_ATTR_GDT 0x02
#define B_ATTR_RES_GDT 0x04
#define B_ATTR_BB 0x08
#define B_ATTR_IB 0x10
#define B_ATTR_IT 0x20
#define B_ATTR_DATA_NOT_USE 0x40
#define B_ATTR_DATA_USE 0x80
#define UNKNOWN 0x00

#define BLOCK_BITMAP 0
#define INODE_BITMAP 1

#define MAX_PATH_LEN 100
#define P_INODE_STATE 0x80000000

#define DEVICE_MODE 0
#define FILE_MODE 1
#define SPUER_MODE 2

#define DUMP_MODE_EXT 1
#define TREE_LIST_MODE_EXT 2

struct ext4_tool
{
    uint8_t mode;     /* 0:设备模式 1:文件模式 2:强制使用超级块的块大小 */
    uint8_t ext_mode; /* 1: dump数据 2:列出树状inode结构 */
    uint32_t dump_bolcknum;
    int fd;
    char path[MAX_PATH_LEN];      /* 要打开的设备路径 */
    uint32_t p_inode;             /* 要打印的inode数量，或者和inode相关的输出，如果=0，则不解析inode */
    uint32_t ssz;                 /* 扇区大小 */
    uint32_t bsz;                 /* 块大小 */
    uint32_t setbsz;              /* 文件模式下有效，通过传参设置，默认4096 */
    unsigned long long bytes;     /* 块设备总大小 */
    uint64_t bolcknum;            /* 块的数量 */
    uint32_t per_block;           /* 每个组块拥有的块数量 */
    uint32_t per_inode;           /* 每个组块拥有的inode数量 */
    uint16_t inode_size;          /* inode的大小 */
    uint32_t groupnum;            /* 组块数量,正常一个块组128M=32768*4K,该值为总大小/128M */
    uint32_t inodeblknum;         /* inode占用的klock的大小 每块中能包含的inode=per_inode/inodeblknum */
    uint32_t group_desc_blk_num;  /* 组描述符所占用的块大小 */
    uint32_t reserved_gdt_blocks; /* 预留块组 */
    uint32_t flex_bg_num;         /* 柔性分组的大小 */
    uint32_t mate_bg_num;         /* 元组块数量，只有开启了mate_bg特性才有用 */
    uint8_t group_desc_len;       /* 组描述符大小 */
    uint8_t *buf;                 /* 按块进行读取 */
    uint8_t *extbuf;              /* 对日志或者目录解析操作时使用 */
    uint8_t *jnl_data_buf;        /* 读取日志块时使用 */
    struct ext4_super_block *sb;
    union feature_compat f_compat;
    union feature_incompat f_incompat;
    union feature_rocompat f_rocompat;
    uint8_t *group_desc_buf; /* 存放组块描述符 */
    uint8_t *block_bit_buf;  /* 存放 blockbitmap */
    uint16_t block_bit_pos;  /* 定位存放 blockbitmap 的位置 */
    uint8_t *inode_bit_buf;  /* 存放 inodebitmap */
    uint16_t inode_bit_pos;  /* 定位存放 inodebitmap 的位置 */
    uint16_t extent_num;
    struct ext4_extent ex[4];
    journal_superblock_t jnlsuper;
    uint64_t *loc_map_buf; /* 叶子节点逻辑映射实际物理块缓存 */
};

#define EXT4_TOOL_LEN sizeof(struct ext4_tool)

struct inode_show_info
{
    int group;
    struct ext4_inode *inode;
    uint32_t inode_num;
    int type;
};

#ifndef BLKROSET
#define BLKROSET _IO(0x12, 93)    /* set device read-only (0 = read-write) */
#define BLKROGET _IO(0x12, 94)    /* get read-only status (0 = read_write) */
#define BLKRRPART _IO(0x12, 95)   /* re-read partition table */
#define BLKGETSIZE _IO(0x12, 96)  /* return device size /512 (long *arg) */
#define BLKFLSBUF _IO(0x12, 97)   /* flush buffer cache */
#define BLKRASET _IO(0x12, 98)    /* set read ahead for block device */
#define BLKRAGET _IO(0x12, 99)    /* get current read ahead setting */
#define BLKFRASET _IO(0x12, 100)  /* set filesystem (mm/filemap.c) read-ahead */
#define BLKFRAGET _IO(0x12, 101)  /* get filesystem (mm/filemap.c) read-ahead */
#define BLKSECTSET _IO(0x12, 102) /* set max sectors per request (ll_rw_blk.c) */
#define BLKSECTGET _IO(0x12, 103) /* get max sectors per request (ll_rw_blk.c) */
#define BLKSSZGET _IO(0x12, 104)  /* get block device sector size */

/* ioctls introduced in 2.2.16, removed in 2.5.58 */
#define BLKELVGET _IOR(0x12, 106, size_t) /* elevator get */
#define BLKELVSET _IOW(0x12, 107, size_t) /* elevator set */

#define BLKBSZGET _IOR(0x12, 112, size_t)
#define BLKBSZSET _IOW(0x12, 113, size_t)
#endif /* !BLKROSET */

#ifndef BLKGETSIZE64
#define BLKGETSIZE64 _IOR(0x12, 114, size_t) /* return device size in bytes (u64 *arg) */
#endif

#define GET_NUN(a, b, c) \
    {                    \
        c = (a) / (b);   \
        if ((a) % (b))   \
            c += 1;      \
    }

static inline void ext4_bitmap_set(uint8_t type, uint8_t attr, struct ext4_tool *dat)
{
    if (BLOCK_BITMAP == type)
    {
        if (dat->block_bit_pos >= dat->per_block)
            dat->block_bit_pos = 0;
        SET_BIT(dat->block_bit_buf[dat->block_bit_pos], attr);
        dat->block_bit_pos++;
    }
    else
    {
        if (dat->inode_bit_pos >= dat->per_inode)
            dat->inode_bit_pos = 0;
        SET_BIT(dat->inode_bit_buf[dat->inode_bit_pos], attr);
        dat->inode_bit_pos++;
    }
}

static inline void ext4_pos_zero(struct ext4_tool *dat)
{
    dat->block_bit_pos = 0;
    dat->inode_bit_pos = 0;
}

#endif

/*
struct feature {
    int		compat;
    unsigned int	mask;
    const char	*string;
};
static struct feature feature_list[] = {
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
            "dir_prealloc" },
    {	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
            "has_journal" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
            "imagic_inodes" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
            "ext_attr" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
            "dir_index" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
            "resize_inode" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
            "lazy_bg" },
    {	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP,
            "snapshot_bitmap" },
    {	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2,
            "sparse_super2" },

    {	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
            "sparse_super" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
            "large_file" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
            "huge_file" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
            "uninit_bg" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
            "uninit_groups" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
            "dir_nlink" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
            "extra_isize" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA,
            "quota" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,
            "bigalloc"},
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,
            "metadata_csum"},
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA,
            "replica" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY,
            "read-only" },
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT,
            "project"},
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS,
            "shared_blocks"},
    {	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY,
            "verity"},

    {	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
            "compression" },
    {	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
            "filetype" },
    {	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
            "needs_recovery" },
    {	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
            "journal_dev" },
    {	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
            "extent" },
    {	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
            "extents" },
    {	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
            "meta_bg" },
    {	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
            "64bit" },
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP,
            "mmp" },
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
            "flex_bg"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE,
            "ea_inode"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA,
            "dirdata"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED,
            "metadata_csum_seed"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR,
            "large_dir"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,
            "inline_data"},
    {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,
            "encrypt"},
    {	0, 0, 0 },
};
*/